# -*- coding: utf-8 -*-


from utils import trimList, flatten, printSeq
from copy import copy
import char_inputs

DEBUG=False

def split_mono(word, dummy=None, dummy2=None):
    return [c for c in word]

def align_mono(grkl, gr):
    if abs(len(grkl)-len(gr))>=1:
        if len(grkl)>len(gr): gr=gr+'!'
        else: grkl=grkl+'!'
    
    if abs(len(grkl)-len(gr))>=1:
         print 'POSSIBLE MISALIGNMENT ON',grkl,gr.encode('utf-8')
         return None
    
    sequence = []
    for i in xrange(len(grkl)):
        sequence.append((grkl[i],gr[i]))
    
    return sequence

def split_bigram(word, dummy=None, dummy2=None):
    parts= []
    buf_chars = []
    for c in word:
        buf_chars.append(c)
        if len(buf_chars)==2:
            parts.append(u''.join(buf_chars))
            buf_chars = []
    if buf_chars:
        parts.append(u''.join(buf_chars))
    return parts

def align_bigram(greeklish,greek):
    parts_gr = split_bigram(greek)
    parts_grkl = split_bigram(greeklish)
    count_gr = 0
    count_grkl = 0
    append_gr = True
    while len(parts_gr)!=len(parts_grkl):
        #print 'Different length!'
        #print parts_gr, parts_grkl
        if append_gr:
            parts_gr.append('!')
            count_gr = count_gr+1
        else :
            parts_grkl.append('!')
            count_grkl = count_grkl+1
        
        if count_gr > 3:
            while '!' in parts_gr: parts_gr.remove('!')
            append_gr = False
        if count_grkl > 3: 
            print 'Giving up on', parts_gr, parts_grkl
            return None
        
            
    sequence = []
    for i in range(0,len(parts_gr)):
        sequence.append((parts_grkl[i],parts_gr[i]))
    return sequence


def split_from_list(word, parts_list):
    """ splits a word in parts from part_list"""
    global DEBUG
    seq = []
    word2 = copy(word)
    while len(word2) > 0:
        found = False
        for l in parts_list:
            if word2.startswith(l):
                seq.append(l)
                word2 = word2[len(l):]
                found = True
                break
        if not found:
            if DEBUG: print 'UNKNOWN REST:', word2.encode('utf-8')
            return None
    if DEBUG: print 'Split_from_list:',;printSeq(seq,True)
    return seq

def split_smart(word, part_list, special_list):
    """ Splits a word into parts from part_list, while preserving (not splitting) 
    any parts that appear in special_list. It runs recursively."""
    global DEBUG
    # in the start, the sequence is the whole word
    seq = [word]   
    oldSeq = None
    found = True
    while found:
        found = False
        if DEBUG: print '\nSequence is:',;printSeq(seq)
        for w in seq:
            if DEBUG: print w.encode('utf-8'),'.',
            # first, split out the special characters, as they need to be preserved.
            for l in special_list:
                #the "not l is w" is to prevent index errors. It's common sense: there's no need to split already split sequences!
                if l in w and not l is w:
                    seq[seq.index(w)] = [w[:w.index(l)],l,w[w.index(l)+len(l):]]
                    seq = trimList(flatten(seq))
                    found = True
                    if not oldSeq==seq:
                        oldSeq = copy(seq)
                    else:
                        #hm, we did our stuff but the sequence hasn't changed: duplicate special char!
                        #so let's get out of here
                        if DEBUG:print 'duplicate!'
                        found=False
                        continue
                    # the sequence has changed, so we need to start over
                    break
            # break one level up
            if(found): break
    final_seq = []
    if DEBUG: print '\nAfter special:',repr(seq),;printSeq(seq,True)
    for w in seq:
        # don't split the specials!
        if(w not in special_list):
            final_seq.append(split_from_list(w, part_list))
        else:
            final_seq.append(w)
    if DEBUG: print '\nFinal seq is:',;printSeq(trimList(flatten(final_seq)),True)            
    return trimList(flatten(final_seq))

def group_parts2(sequence, special_chars=[]):
    """takes a sequence of aligned chars and dipthongs and tries to group them together in pairs, 
    preserving already existing pairs. The sequence is the format of [('t',u'τ'),('r',u'ρ'),]
    special_chars is a list of dipthongs and chars that should be left alone.
    """
    sequence2=[]
    i = 0
    grkl1 = None;grkl2=None;gr1=None;gr2=None
    # len-1 because we use +1 later
    while(i<len(sequence)-1):
        #fetch two parts
        grkl1,gr1 = sequence[i]
        grkl2,gr2 = sequence[i+1]
        # if both the two parts, in greek and greeklish are single chars
        # PLUS they do not appear in the special chars list
        if(len(grkl1)==1 and len(grkl2)==1 and len(gr1)==1 and len(gr2)==1
           and grkl1 not in special_chars and grkl2 not in special_chars
           and gr1 not in special_chars and gr2 not in special_chars):            
            # we can join them together
            sequence2.append((grkl1+grkl2,gr1+gr2))
            grkl1 = None;grkl2=None;gr1=None;gr2=None
        else:
            # but if not, just append the first part, and forward one step only
            sequence2.append((grkl1,gr1))
            i-=1
        #forward two steps since we get them in pairs
        i+=2
    # append any leftovers that might exist
    try:
        grkl,gr = sequence[i]
        sequence2.append((grkl,gr))
    except:
        pass
    return sequence2



def align3(greeklish, greek):
    """takes two words, one greeklish, and one greek and tries to align them so that their "special chars" are in the same position.
    it returns a sequence of the form [('th',u'θ'),('r',u'ρ'),].
    Uses 'char_inputs.py'. Tweaking that file will greatly change this function's behavior."""
    sequence = []
    idx_grkl = 0
    idx_gr = 0
    while idx_grkl<len(greeklish) and idx_gr<len(greek):
        # get two dipthongs
        syll_grkl = greeklish[idx_grkl:idx_grkl+2]
        syll_gr = greek[idx_gr:idx_gr+2]
        #if the greeklish one may map on a single greek char (dipthongs)
        if syll_grkl in char_inputs.dipthongs:
            syll_gr = greek[idx_gr]
            syll_gr2 = greek[idx_gr:idx_gr+2]
            #if the greek dipthong is also a double (dipthongs_normal)
            if syll_gr2 == char_inputs.dipthongs_normal.get(syll_grkl, None):
                #then they are two matching dipthongs, we match them anc continue
                sequence.append((syll_grkl, syll_gr2))
                idx_gr +=2
                idx_grkl +=2
                continue
            #if the greek char  is the the single char the greeklish dipthong matches
            elif syll_gr == char_inputs.dipthongs[syll_grkl]: # WE GOT MATCH!
                #then we have a greeklish dipthong matching a greek char, we match them anc continue
                sequence.append((syll_grkl, syll_gr))
                idx_grkl +=2
                idx_gr +=1
                continue
        
        #The greeklish dipthong isn't on the list, but the greek may be
        
        #if the greek dipthong mathces a single greeklish char (dipthongs_rev)
        elif syll_gr in char_inputs.dipthongs_rev:
            syll_grkl = greeklish[idx_grkl]
            syll_grkl2 = greeklish[idx_grkl:idx_grkl+2]
            #if the greeklish dipthongs is also a double (dipthongs_rev_normal)
            if syll_grkl2 == char_inputs.dipthongs_rev_normal.get(syll_gr, None):
                #then we have a greek dipthong matching a greeklish dipthong, we match them and continue
                sequence.append((syll_grkl2, syll_gr))
                idx_gr +=2
                idx_grkl +=2
                continue
            #if the greeklish char is the single char the greek dipthong matches
            elif syll_grkl == char_inputs.dipthongs_rev[syll_gr] : # WE GOT MATCH!
                #then we have a greek dipthong matching a greklish char, we match them and continue
                sequence.append((syll_grkl, syll_gr))
                idx_gr +=2
                idx_grkl +=1
                continue
        
        #boring, one greeklish char to one greek char
        sequence.append((greeklish[idx_grkl],greek[idx_gr]))
        idx_grkl +=1
        idx_gr +=1    
    # Hmm, the lengths don't match. This happens in case of bugs, or in case of malformed words.
    # We flag the word and return nothing, as we don't like malformed data
    if idx_gr<len(greek) or idx_grkl<len(greeklish): 
        print 'POSSIBLE MISALIGNMENT ON',greeklish,greek.encode('utf-8')
        return None
    # we group the single chars together.
    sequence2=group_parts2(sequence, char_inputs.special_chars)
    
    return sequence2

###### END OF ALIGNMENT METHODS ######
